﻿/*
 * This file is part of MonoStrategy.
 *
 * Copyright (C) 2010-2011 Christoph Husse
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: 
 *      # Christoph Husse
 * 
 * Also checkout our homepage: http://monostrategy.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Globalization;
using System.Drawing;
using System.IO;
using System.ComponentModel;
using System.Drawing.Imaging;
using MonoStrategy;

namespace MonoStrategy
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static DependencyProperty CurrentSequenceProperty = DependencyProperty.Register("CurrentSequence", typeof(GFXSequence), typeof(MainWindow));
        public static MainWindow Instance { get; private set; }

        private DispatcherTimer m_UpdateTimer500 = new DispatcherTimer();
        private GFXFile m_GFXFile;
        private Boolean m_IsLoading;
        private Boolean m_HasGFXFileChanged;

        public BindingList<GFXSequence> GUISeqs { get; private set; }
        public BindingList<GFXSequence> ObjectSeqs { get; private set; }
        public BindingList<GFXSequence> TorsoSeqs { get; private set; }
        public BindingList<GFXSequence> ShadowSeqs { get; private set; }
        public BindingList<GFXSequence> LandscapeSeqs { get; private set; }

        public GFXSequence CurrentSequence
        {
            get
            {
                return (GFXSequence)GetValue(CurrentSequenceProperty);
            }
            set
            {
                SetValue(CurrentSequenceProperty, value);
            }
        }

        public MainWindow()
        {
            VisualUtilities.Instance = new AnimationUtilities();
            AnimationLibrary.OpenFromDirectory("./AnimationDirectory/");

            if (Instance != null)
                throw new ApplicationException("AnimationEditor is already opened.");

            Instance = this;

            Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException);

            GUISeqs = new BindingList<GFXSequence>();
            ObjectSeqs = new BindingList<GFXSequence>();
            TorsoSeqs = new BindingList<GFXSequence>();
            ShadowSeqs = new BindingList<GFXSequence>();
            LandscapeSeqs = new BindingList<GFXSequence>();

            InitializeComponent();

            DataContext = this;
            m_UpdateTimer500.Interval = TimeSpan.FromMilliseconds(500);
            m_UpdateTimer500.Tick += new EventHandler(m_UpdateTimer500_Tick);
            m_UpdateTimer500.Start();

            m_GFXFile = new GFXFile();
        }

        private void LoadGFXFile(String inFileName)
        {
            m_HasGFXFileChanged = false;
            m_IsLoading = true;
            m_GFXFile.BeginLoad(inFileName);
        }

        void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            Log.LogExceptionModal(e.Exception);
            e.Handled = true;
        }

        void m_UpdateTimer500_Tick(object sender, EventArgs e)
        {
            PROGRESS_GfxLoad.Value = m_GFXFile.Progress;

            if (m_IsLoading && m_GFXFile.IsLoaded)
            {
                m_IsLoading = false;

                TEXT_GfxFilePath.Text = m_GFXFile.FileName;

                LandscapeSeqs.Clear();
                GUISeqs.Clear();
                ObjectSeqs.Clear();
                TorsoSeqs.Clear();
                ShadowSeqs.Clear();

                foreach (var seq in m_GFXFile.LandscapeSeqs)
                {
                    LandscapeSeqs.Add(seq);
                }

                foreach (var seq in m_GFXFile.GUISeqs)
                {
                    GUISeqs.Add(seq);
                }

                foreach (var seq in m_GFXFile.ObjectSeqs)
                {
                    ObjectSeqs.Add(seq);
                }

                foreach (var seq in m_GFXFile.TorsoSeqs)
                {
                    TorsoSeqs.Add(seq);
                }

                foreach (var seq in m_GFXFile.ShadowSeqs)
                {
                    ShadowSeqs.Add(seq);
                }

                TAB_Landscapes.Header = "Landscapes (" + LandscapeSeqs.Count + ")";
                TAB_GfxGUI.Header = "GUI (" + GUISeqs.Count + ")";
                TAB_GfxObjects.Header = "Objects (" + ObjectSeqs.Count + ")";
                TAB_GfxShadows.Header = "Shadows (" + ShadowSeqs.Count + ")";
                TAB_GfxTorso.Header = "Torso (" + TorsoSeqs.Count + ")";
            }
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if(m_HasGFXFileChanged)
                m_GFXFile.Save();

            TAB_AnimLibrary.Close();
        }

        private void BTN_GfxLoad_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog dlg = new System.Windows.Forms.OpenFileDialog()
            {
                Title = "Open GFX-File...",
                Multiselect = false,
                //dlg.InitialDirectory = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
                CheckFileExists = true,
                CheckPathExists = true,
                Filter = "Settlers 3 GFX Files (*.dat)|*.dat|All Files (*.*)|*.*",

            };

            if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
                return;

            if (!File.Exists(dlg.FileName))
                throw new FileNotFoundException("The given file does not exist.", dlg.FileName);

            LoadGFXFile(dlg.FileName);
        }

        private void BTN_GfxRemoveSequence_Click(object sender, RoutedEventArgs e)
        {
            if (CurrentSequence == null)
                return;

            if (LandscapeSeqs.Contains(CurrentSequence))
            {
                m_GFXFile.LandscapeSeqs.Remove(CurrentSequence);
                LandscapeSeqs.Remove(CurrentSequence);
            }
            else if (GUISeqs.Contains(CurrentSequence))
            {
                m_GFXFile.GUISeqs.Remove(CurrentSequence);
                GUISeqs.Remove(CurrentSequence);
            }
            else if (ObjectSeqs.Contains(CurrentSequence))
            {
                m_GFXFile.ObjectSeqs.Remove(CurrentSequence);
                ObjectSeqs.Remove(CurrentSequence);
            }
            else if (TorsoSeqs.Contains(CurrentSequence))
            {
                m_GFXFile.TorsoSeqs.Remove(CurrentSequence);
                TorsoSeqs.Remove(CurrentSequence);
            }
            else if (ShadowSeqs.Contains(CurrentSequence))
            {
                m_GFXFile.ShadowSeqs.Remove(CurrentSequence);
                ShadowSeqs.Remove(CurrentSequence);
            }

            TAB_Landscapes.Header = "Landscapes (" + LandscapeSeqs.Count + ")";
            TAB_GfxGUI.Header = "GUI (" + GUISeqs.Count + ")";
            TAB_GfxObjects.Header = "Objects (" + ObjectSeqs.Count + ")";
            TAB_GfxShadows.Header = "Torso (" + ShadowSeqs.Count + ")";
            TAB_GfxTorso.Header = "Shadows (" + TorsoSeqs.Count + ")";

            m_HasGFXFileChanged = true;
            CurrentSequence = null;
        }

        private void BTN_GfxRemoveFrame_Click(object sender, RoutedEventArgs e)
        {
            var frame = (GFXFrame)LIST_SeqFrames.SelectedItem;
            var seq = CurrentSequence;

            if (frame == null)
                return;

            m_HasGFXFileChanged = true;
            seq.Frames.Remove(frame);
            CurrentSequence = null;
            CurrentSequence = seq;
        }

        private void BTN_GfxExportAllSeqs_Click(object sender, RoutedEventArgs e)
        {
            List<GFXSequence>[] seqList = new List<GFXSequence>[] { 
                m_GFXFile.LandscapeSeqs, m_GFXFile.GUISeqs, m_GFXFile.ObjectSeqs, m_GFXFile.TorsoSeqs, m_GFXFile.ShadowSeqs
            };

            for(int i = 0; i < 5; i++)
            {
                if (seqList[i].Count == 0)
                    continue;

                foreach (var seq in seqList[i])
                {
                    GfxExportSequence(seq);
                }
            }
        }

        private void BTN_GfxExportSeq_Click(object sender, RoutedEventArgs e)
        {
            if (CurrentSequence == null)
                return;

            GfxExportSequence(CurrentSequence);
        }

        private void GfxExportSequence(GFXSequence inSequence)
        {
            String gfxDir = System.IO.Path.GetDirectoryName(m_GFXFile.FileName) + "/" + System.IO.Path.GetFileNameWithoutExtension(m_GFXFile.FileName);
            String[] names = new String[] { "Landscapes", "GUI", "Objects", "Torso", "Shadows" };
            List<GFXSequence>[] seqList = new List<GFXSequence>[] { 
                m_GFXFile.LandscapeSeqs, m_GFXFile.GUISeqs, m_GFXFile.ObjectSeqs, m_GFXFile.TorsoSeqs, m_GFXFile.ShadowSeqs
            };

            if (File.Exists(gfxDir))
                throw new ArgumentException("A file with the target directory name \"" + gfxDir + "\" does already exist!");

            for (int i = 0; i < 5; i++)
            {
                String name = names[i];

                if (!seqList[i].Contains(inSequence))
                    continue;

                Directory.CreateDirectory(gfxDir + "/" + name + "/" + inSequence.Index);

                foreach (var frame in inSequence.Frames)
                {
                    frame.Image.Save(gfxDir + "/" + name + "/" + inSequence.Index + "/" + frame.Index + "_" + frame.OffsetX + "_" + frame.OffsetY + ".png");
                }
            }
        }

        private void BTN_GfxFrameToClipboard_Click(object sender, RoutedEventArgs e)
        {
            var frame = (GFXFrame)LIST_SeqFrames.SelectedItem;

            if (frame == null)
                return;

            System.Windows.Forms.Clipboard.SetImage(frame.Image);
        }
    }



    public class DrawingToImageSource : IValueConverter
    {
        public static readonly DrawingToImageSource Instance = new DrawingToImageSource();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            System.Drawing.Bitmap bitmap = value as System.Drawing.Bitmap;

            if (bitmap == null)
                return null;

            MemoryStream stream = new MemoryStream();

            bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);

            return BitmapFrame.Create(stream);
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
